<template>
    <div class="tag_view" ref="el" @contextmenu.native.prevent="showContext">
        <div class="tag-view-container">
            <el-scrollbar :native="true" :noresize="false" tag="section" ref="scrollbarRef"
                style="width:100%;height:100%" @wheel.native.prevent="handleScroll" class="scrollbar">
                <div class="tag-view-body forbid-select" ref="draggableRef">
                    <el-tag :type="getTagColor(element)" @close="closeTagMenu(element)" @dblclick="refreshTag"
                        :class="tagClass(element, index)" @click="intoRoute(element)" :key="index" closable v-ripple
                        :data-tag="element.path" v-for="(element, index) in tagMenu"
                        @contextmenu.prevent.stop="tagRightClick($event, element)">
                        <el-icon class="tag-view-menu-icon">
                            <component :is="getIcon(element.icon)" />
                        </el-icon>
                        <span class="no-wrap tag-name">
                            {{ element.name + (element.title ? " - " + element.title : "") }}
                        </span>
                    </el-tag>
                </div>
            </el-scrollbar>
        </div>

        <teleport to="body">
            <ul v-show="tagMenuRightContext.visible" class="el-dropdown-menu el-popper tagMenuRightContext"
                :style="{ left: tagMenuRightContext.left + 'px', top: tagMenuRightContext.top + 'px', width: 'fit-content', padding: '5px 0' }">
                <li class="el-dropdown-menu__item" @click="closeOtherTag" v-if="tagMenuRightContext.other">
                    关闭其他标签
                </li>
                <li class="el-dropdown-menu__item" @click="closeAllTag">
                    关闭所有标签
                </li>
            </ul>
        </teleport>
    </div>
</template>

<script setup>
import router from "@/router"
import { deepCopy, getIcon } from "@/utils/tools"
import { increase, decrease } from "@/utils/setting"
import { useWait, useModalSize } from "@usehook"
import { broadcastEmitter } from "@/utils/eventbus"
import { useDraggable } from 'vue-draggable-plus'
import { useTemplateRef } from "vue"
import instance, { storeToRefs } from "@/pinia"

let timeoutEvent = $ref(null)
let clickable = $ref(true)
const { tagMenuStore } = instance
const hiddenElement = (ele) => {
    if (!ele) return
    ele.classList.add("dragModal")
    for (let children of ele.children) {
        children.classList.add("hidden")
    }
}

const showElement = (ele) => {
    if (!ele) return
    ele.classList.remove("dragModal")
    for (let children of ele.children) {
        children.classList.remove("hidden")
    }
}

const tagWidth = {}

const start = (el) => {
    hiddenElement(document.querySelector(".inner-main"))
    const tagViews = document.querySelectorAll(".tag-view-body .el-tag.menu-tag:not(.dragClass)")
    const dragClass = document.querySelector('.dragClass')
    //清除延时器,并设置变量为空
    clearTimeout(timeoutEvent)
    timeoutEvent = null
    //拖动时禁止点击页签跳转
    clickable = false
    let scrollWidth = scrollWrapper.scrollWidth
    let clientWidth = scrollWrapper.clientWidth
    let tagSize = tagMenu.value.length
    let percentWidth = (clientWidth - (tagSize - 1) * 5) / tagSize
    let left = el.originalEvent.x
    let top = el.originalEvent.y - 50

    //调整拖动时页签的宽度
    tagViews.forEach((e) => {
        e.style.backgroundColor = '#eee'
    })

    //调整被拖起的页签的宽度
    nextTick(() => {
        dragClass.style.top = top + 'px'
        dragClass.style.left = left + 'px'
    })
    if (scrollWidth > clientWidth) {
        dragClass.style.width = `${percentWidth}px`//dragClass.getBoundingClientRect().width > percentWidth ? `${percentWidth}px` : dragClass.getBoundingClientRect().width

        //调整拖动时页签的宽度
        tagViews.forEach((e) => {
            e.style.transition = "500ms ease-out width"
            const width = `${e.getBoundingClientRect().width}px`
            tagWidth[e.getAttribute("data-tag")] = width
            e.style.width = width
            nextTick(() => {
                e.style.width = `${percentWidth}px`//e.getBoundingClientRect().width > percentWidth ? `${percentWidth}px` : width
            })
        })

        let close = document.querySelectorAll(".tag-view-body .el-tag .el-tag__close")

        //隐藏页签关闭按钮
        for (let ele of close) {
            ele.style.pointerEvents = 'none'
        }
    }
}
const end = () => {
    showElement(document.querySelector(".inner-main"))
    const tagViews = document.querySelectorAll(".tag-view-body .el-tag")
    //延迟恢复页签跳转,及背景色,宽度
    timeoutEvent = setTimeout(() => {
        clickable = true
        tagViews.forEach((e) => {
            e.style.transition = ""
            e.style.backgroundColor = ''
            e.style.width = ""
        })
    }, 10)

    let close = document.querySelectorAll(".tag-view-body .el-tag .el-tag__close")
    //恢复页签关闭按钮
    for (let ele of close) {
        ele.style.pointerEvents = ''
    }
    tagMenuStore.updateTagMenu(tagMenu.value)
    setTimeout(() => {
        initTagMenuPlace(router.currentRoute.value)
    }, 10)
}

// 右击菜单的位置
let tagMenuRightContext = $ref({ visible: false, left: 0, top: 0, contextmenuWidth: 130, other: false })
// tagMenu的内容，监听store的变化实时更新
const { getTagMenu: tagMenu } = storeToRefs(tagMenuStore)

// 当前右击的tag
let currTag = $ref({})
// 关闭指定的tagMenu的触发事件
const closeTagMenu = (tag) => {
    tagMenuRightContext.visible = false
    if (tag.path === router.currentRoute.value.fullPath) {
        //获取tagMenu最后一项
        const index = { path: '/' }
        let nextMenu = tagMenu.value.at(tagMenu.value.indexOf(tag) + 1) || tagMenu.value.at(tagMenu.value.indexOf(tag) - 1) || index
        if (nextMenu.path === tag.path) nextMenu = index
        router.push(nextMenu.path)
    }
    tagMenuStore.closeTagMenu(tag)
}

// 点击关闭其他标签的触发事件
const closeOtherTag = () => {
    router.push(currTag.path || "/")
    tagMenuStore.closeOtherTagMenu(currTag)

}
//点击关闭所有标签的触发事件
const closeAllTag = () => {
    router.push('/')
    tagMenuStore.clearTagMenu()
}
//滚动条ref对象，操作滚动条位置
const scrollbarRef = $ref(null)
//取出滚动条对象，方便后续操作
const scrollWrapper = $computed(() => {
    return scrollbarRef.wrapRef
})
//滚动条滚动事件
const handleScroll = (e) => {
    const eventDelta = e.wheelDelta || -e.deltaY * 40
    // 目前两种都能调整滚动位置
    // scrollWrapper.scrollLeft = scrollWrapper.scrollLeft - eventDelta / 4
    scrollbarRef.setScrollLeft(scrollWrapper.scrollLeft - eventDelta / 4)
}

const tagClass = (element, index) => {
    return `cursor-pointer tag-view-menu menu-tag no-wrap tag-view-menu-index-${index} ${element.path === router.currentRoute.value.fullPath ? 'gradient-border' : ''}`
}

//获取tagMenu的颜色
const getTagColor = (tag) => {
    return tag.path === currTag.path && tagMenuRightContext.visible ? "warning" : tag.path === router.currentRoute.value.fullPath ? 'primary' : 'info'
}
//右击事件，弹出右击菜单
const tagRightClick = (e, tag) => {
    currTag = deepCopy(tag)
    showContext(e, true)
}
//tagMenu的ref对象，获取tagMenu的宽度
const el = $ref(null)
//计算右击菜单位置
const showContext = (e, cTag) => {
    if (tagMenu.value.length <= 1) return
    tagMenuRightContext.other = Boolean(cTag)
    tagMenuRightContext.visible = false
    const menuMinWidth = 135
    const offsetWidth = el.offsetWidth // container width
    const maxLeft = offsetWidth - menuMinWidth // left boundary
    const left = e.clientX  // 15: margin right

    if (left > maxLeft) {
        tagMenuRightContext.left = maxLeft
    } else {
        tagMenuRightContext.left = left
    }

    const top = e.clientY + 10
    if (top < 10) {
        tagMenuRightContext.top = 10
    } else {
        tagMenuRightContext.top = top
    }
    tagMenuRightContext.visible = true
}
//初始化滚动到当前路由在tagMenu的位置
const initTagMenuPlace = (currentRoute) => {
    const index = tagMenu.value.findIndex((tag) => {
        return tag.path === currentRoute.fullPath
    })
    if (index >= 0) {
        const tagElement = document.querySelector(".tag-view-menu-index-" + index)
        setTimeout(() => {
            if (tagElement) scrollbarRef.scrollTo({
                left: tagElement.offsetLeft - (index + 1 === tagMenu.value.length ? 0 : 500),
                behavior: 'smooth' // 确保平滑滚动
            })
        }, 0)
    }
}

const intoRoute = (element) => {
    if (!router.hasRoute(element.name + element.parentId) || !clickable) return
    router.push(element.path)
}
//刷新页面
const refreshTag = () => {
    broadcastEmitter("refresh")
}
//添加当前路由到tagMenu中
watch(() => router.currentRoute.value, (value) => {
    tagMenuStore.addTagMenu(value)
    nextTick(() => {
        initTagMenuPlace(value)
    })
})
//关闭tagMenu的右击菜单
const closeMenu = async (e) => {
    if (e.button === 2) {
        for (let ele of document.querySelectorAll(".tag-view-menu")) {
            if (ele.contains(e.target)) return
        }
    }
    if (e.button === 0 && document.querySelector(".tagMenuRightContext").contains(e.target)) {
        await useWait(10)
    }
    if (e.button === 2 && document.querySelector(".tagMenuRightContext").contains(e.target)) return
    tagMenuRightContext.visible = false
    currTag = {}
}

watch(() => tagMenuRightContext.visible, (visible) => {
    if (visible) {
        addEventListener('mouseup', closeMenu)
    } else {
        removeEventListener('mouseup', closeMenu)
    }
})

const checkFn = (str) => {
    const regex = /^[Ff](1[0-2]|[1-9])$/
    return regex.test(str)
}

const checkNumber = (str) => {
    return /^\d+$/.test(str);  // 正则表达式匹配纯数字
}

const keyDown = (e) => {
    const { key, altKey, metaKey, ctrlKey } = e
    if (["Alt", "Control", "Meta"].includes(key) || checkFn(key) || (checkNumber(key) && (altKey || ctrlKey || metaKey))) {
        e.preventDefault()
    }

    // 跳转tagMenu快捷键 alt+数字或者ctrl+数字
    if ((checkNumber(key) && (altKey || ctrlKey || metaKey)) && !useModalSize.get()) {
        const index = parseInt(key)
        const url = tagMenu.value[index - 1]
        if (url) router.push(url.path)
    }

    if (key === "-" && ctrlKey) {
        e.preventDefault()
        if (import.meta.env.MODE !== 'production') decrease()
    }

    if (key === "=" && ctrlKey) {
        e.preventDefault()
        if (import.meta.env.MODE !== 'production') increase()
    }

    if (key === "F1") {
        draggable.resume()
        if (document.querySelector('.dragClass')) document.querySelector('.dragClass').style.opacity = 1
    }
}

const keyUp = (e) => {
    const { key } = e
    if (key === "F1") {
        draggable.pause()
        if (document.querySelector('.dragClass')) document.querySelector('.dragClass').style.opacity = 0
    }
}

onMounted(() => {
    addEventListener("keydown", keyDown)
    addEventListener("keyup", keyUp)
})

const draggable = useDraggable(useTemplateRef("draggableRef"), tagMenu, {
    chosenClass: "chosenClass",
    ghostClass: "ghostClass", dragClass: "dragClass",
    animation: 150,
    onStart: start,
    onEnd: end,
    forceFallback: true,
    disabled: true
})
</script>

<style scoped lang="scss">
.tagMenuRightContext {
    z-index: 12;
}

.HomeTag {
    min-width: 90px;
    text-align: center;
}

.tag_view {
    height: 0;
    opacity: 0;
    background: var(--tag-view-background);
    padding: 0 5px;
    backdrop-filter: var(--overlay-background-filter-blur);
    transition: all .5s ease-in-out;
    animation-duration: 1s;
}

.withTagMenu .tag_view {
    height: calc((var(--font-size) + 1px) * 2 + 6px) !important;
    opacity: 1 !important;
}

.tag-view-container {
    width: 100%;
    padding: 3px 0;
    height: calc(100% - 6px);
}

.tag-view-body {
    height: calc(var(--font-size) * 2 + 2px);
    height: 100%;
}

.tag-view-menu {
    height: 100%;
    font-size: var(--font-size);
    display: inline-block;
}

.menu-tag {
    margin-left: 5px;
    text-align: center;
}

:deep(.el-dropdown-menu__item:hover) {
    background: var(--background);
}

:deep(.el-tag__content) {
    display: contents;
    height: 100%;
    line-height: calc(var(--font-size) * 2);
}

:deep(.chosenClass) {
    background: rgba(199, 199, 199, .9) !important;
}

:deep(.el-tag .el-icon.tag-view-menu-icon) {
    border-radius: 50% !important;
    cursor: default;
    font-size: calc(var(--font-size) - 2px);
    height: var(--font-size);
    width: var(--font-size);
}

:deep(.tag-view-body .el-tag) {
    display: inline-flex;
}

:deep(.tag-view-body .el-tag:first-child) {
    margin-left: 0 !important;
}

:deep(.dragModal) {
    width: 100%;
    height: 100%;
    background: rgba(179, 179, 179, .7);
    pointer-events: none;
    z-index: 0 !important;
}

:deep(.tag-view-menu .el-tag__close) {
    z-index: 1
}
</style>

<style lang="scss">
.tag-view-container .el-scrollbar.scrollbar .el-scrollbar__wrap {
    overflow-x: hidden;
    margin-bottom: 0 !important;
    overflow-y: hidden !important;
    margin-right: 0 !important;
}

.tag-view-container .el-scrollbar .el-scrollbar__wrap .el-scrollbar__view {
    white-space: nowrap;
}
</style>